#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <math.h>
#include "string.h"
#include "expression.h"


#define isDigit(abc) (abc <= '9' && abc>= '0')
#define isOperator(abc) (abc == '+' || abc == '-' || abc == '*' || abc == '/'  || abc == '%' || abc == '^')
#define isLeftParenthesis(abc) (abc == '(')
#define isRightParenthesis(abc) (abc == ')')
using namespace std;

int getLevel(const char op)
{
    switch(op)
    {
        case '^':
          return 3;
        case '*':
        case '/':
        case '%':
          return 2;
        case '+':
        case '-':
          return 1;
    }
}

int calculate(std::stack<int>& num, std::stack<char>& op)
{
   int a = num.top();
   num.pop();
   int b = num.top();
   num.pop();
   const char c = op.top();
   op.pop();
   switch(c)
   {
     case '^':
       num.push(pow(b,a));
       break;
     case '+':
       num.push(a+b);
       break;
     case '-':
       num.push(b-a);
       break;
     case '*':
         num.push(a*b);
         break;
     case '/':
       if(a==0)
         return -1;
       num.push(b / a) ;
       break;
     case '%':
       if(a==0)
         return -1;
       num.push(b % a);
       break;
   }
   return 0;
}

int evaluate(const char* expression, int* result)
{
    std::stack<char> op;
    std::stack<int> num;
    char temp ;
    const char* pos = expression;
    const char* end = expression+strlen(expression);
    if( pos - end > 50) return -1;
    while(pos < end)
    {
        temp = *pos;
        if(isDigit(temp)){
          std::string str;
          while(isDigit(*pos) && pos < end )
           {
              str.push_back(*pos);
              pos++;
           }
          if( strlen(str.c_str()) > 10) return -1;
          num.push(atoi(str.c_str()));
          pos--;
        } else if(isLeftParenthesis(temp))
        {
          op.push(temp);
        } else if(isRightParenthesis(temp))
        {
          while(!op.empty() && op.top() != '(' )
          {
        	  int temp = calculate(num,op);
              if (0!=temp)
            	return temp;
          }
          op.pop();
        } else if(isOperator(temp))
        {
           while(!op.empty() &&  (getLevel(temp) <= getLevel(op.top()))  )
           {
              if(isLeftParenthesis(op.top())) break;
        	  int temp = calculate(num,op);
              if (0!=temp)
            	return temp;
           }
           op.push(temp);
        }

        pos ++;

    }
    while(!op.empty())
    {
  	  int temp = calculate(num,op);
        if (0!=temp)
      	return temp;
    }
    *result=num.top();
    return 0;

}



